use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::{Arc, Mutex};

use lazy_static::lazy_static;

use crate::class::vm_class::VMClass;
use crate::vm_class_loader::ClassLoader;
use crate::vm_object::VMObject;
use crate::vm_thread::VMThread;
use crate::vm_val::{BYTE_ZERO, DOUBLE_ZERO, FALSE, FLOAT_ZERO, INTEGER_ZERO, LONG_ZERO, NULL_REF, VMValByte, VMValChar, VMValEnum, VMValInteger, VMValLong};
use crate::vm_val::VMValRef;

lazy_static! {
    static ref VM_HEAP: Mutex<VMHeap> = {
        Mutex::new(VMHeap { heap: RefCell::new(vec![]) })
    };
}
pub struct VMHeap {
    heap: RefCell<Vec<Arc<VMObject>>>,
}

impl VMHeap {
    /// 在堆中创建java String对象
    pub fn create_jstring(rust_str: &String, thread: &VMThread) -> Result<VMValEnum, String> {
        let mut class_loader = thread.vm.class_loader.borrow_mut();
        let jstring_value_ref = {
            let mut bytes = vec![];
            let utf16_value = rust_str.encode_utf16();
            for ch in utf16_value {
                for b in ch.to_be_bytes() {
                    bytes.push(i8::from_be_bytes([b]));
                }
            }
            let barr_class = class_loader.load_class(&String::from("[B"))?;
            let value = VMHeap::new_array_object(barr_class, bytes.len() as i32)?;
            let value_ref = VMValEnum::convert2ref(&value);
            let arr_obj = VMHeap::get_vmobject(value_ref.clone())?;

            let mut index = 0_usize;
            for b in bytes {
                arr_obj.slots.borrow_mut()[index] = VMValEnum::VMValByte { val: VMValByte { num: b } };
                index += 1;
            }
            value_ref
        };

        let str_class = class_loader.load_class(&String::from("java/lang/String"))?;
        let val_enum = VMHeap::new_object(str_class.clone())?;
        let obj_ref = VMValEnum::convert2ref(&val_enum);
        let obj = VMHeap::get_vmobject(obj_ref.clone())?;

        let ro_fields = &str_class.fields.borrow();
        for field in ro_fields.iter() {
            let ro_field = field.borrow();
            if ro_field.name == String::from("value") {
                obj.slots.borrow_mut()[ro_field.slot_id as usize] = VMValEnum::VMValRef { val: jstring_value_ref.clone() };
            }
            if ro_field.name == String::from("coder") {
                obj.slots.borrow_mut()[ro_field.slot_id as usize] = VMValEnum::VMValByte { val: VMValByte { num: 1 } };
            }
            if ro_field.name == String::from("hash") {
                obj.slots.borrow_mut()[ro_field.slot_id as usize] = VMValEnum::VMValInteger { val: VMValInteger { num: 0 } };
            }
        }

        return Ok(VMValEnum::VMValRef { val: VMValRef { num: obj_ref.num } });
    }

    /// 把java字符串对象转化为rust字符串对象
    pub fn convert_jstring2rstring(jstr: VMValEnum) -> String {
        match jstr {
            VMValEnum::VMValRef { val: val_ref } => {
                let obj = VMHeap::get_vmobject(val_ref).unwrap();
                if obj.vm_class.name == String::from("java/lang/String") {
                    let ro_fields = obj.vm_class.fields.borrow();
                    for field in ro_fields.iter() {
                        let ro_field = field.borrow();
                        if ro_field.name == String::from("value") {
                            let ro_slots = obj.slots.borrow();
                            let bytes_arr_ref = ro_slots.get(ro_field.slot_id as usize).unwrap();
                            let ch_arr = VMHeap::get_vmobject(VMValEnum::convert2ref(bytes_arr_ref)).unwrap();
                            let mut utf16 = vec![];
                            let ro_slots = ch_arr.slots.borrow();
                            for i in 0..(ch_arr.arr_len as usize) {
                                if i % 2 > 0 {
                                    continue;
                                }
                                let v1 = VMValEnum::convert2integer(ro_slots.get(i).unwrap()).num as i8;
                                let v2 = VMValEnum::convert2integer(ro_slots.get(i + 1).unwrap()).num as i8;

                                let ch = u16::from_be_bytes([v1.to_be_bytes()[0], v2.to_be_bytes()[0]]);
                                utf16.push(ch);
                            }
                            return String::from_utf16(&utf16).unwrap();
                        }
                    }
                    panic!("没有找到value字段:{},{}", file!(), line!());
                } else {
                    panic!("类型异常,不是java/lang/String实例,{},{}", file!(), line!());
                }
            }
            _ => {
                panic!("类型不匹配:{},{}", file!(), line!());
            }
        };
    }

    pub fn new_object(vm_class: Rc<VMClass>) -> Result<VMValEnum, String> {
        return VMHeap::_inner_new_vm_object(vm_class, 0, false, None);
    }


    pub fn new_class_object(vm_class: Rc<VMClass>, jclass: Option<Rc<VMClass>>) -> Result<VMValEnum, String> {
        return VMHeap::_inner_new_vm_object(vm_class, 0, false, jclass);
    }

    pub fn new_array_object(vm_class: Rc<VMClass>, arr_len: i32) -> Result<VMValEnum, String> {
        return VMHeap::_inner_new_vm_object(vm_class, arr_len, true, None);
    }

    fn _inner_new_vm_object(vm_class: Rc<VMClass>, arr_len: i32, is_arr: bool, jclass: Option<Rc<VMClass>>) -> Result<VMValEnum, String> {
        let lock = VM_HEAP.lock();
        let val = lock.unwrap();
        let slots_size = if is_arr {
            arr_len as usize
        } else {
            *(vm_class.instance_slot_count.borrow()) as usize
        };
        let index = val.heap.borrow().len();
        let default_val = VMHeap::get_default_val(vm_class.clone());
        val.heap.borrow_mut().push(Arc::new(VMObject {
            vm_class,
            jclass,
            slots: RefCell::new(vec![default_val; slots_size]),
            arr_len,
            is_arr,
        }));
        Ok(VMValEnum::VMValRef { val: VMValRef { num: index } })
    }

    pub fn get_vmobject(val_ref: VMValRef) -> Result<Arc<VMObject>, String> {
        let lock = VM_HEAP.lock();
        let val = lock.unwrap();
        let ro_heap = val.heap.borrow();
        let obj_option = ro_heap.get(val_ref.num);
        if obj_option.is_none() {
            return Err(String::from("对象不存在"));
        }
        return Ok(obj_option.unwrap().clone());
    }

    fn get_default_val(vm_class: Rc<VMClass>) -> VMValEnum {
        let class_name = &vm_class.name;
        if class_name.starts_with("[") {
            return match class_name.as_str() {
                "[Z" => { VMValEnum::VMValBoolean { val: FALSE } }
                "[B" => { VMValEnum::VMValByte { val: BYTE_ZERO } }
                "[C" => { VMValEnum::VMValChar { val: VMValChar { val: 0 } } }
                "[S" => { VMValEnum::VMValInteger { val: INTEGER_ZERO } }
                "[I" => { VMValEnum::VMValInteger { val: INTEGER_ZERO } }
                "[J" => { VMValEnum::VMValLong { val: LONG_ZERO } }
                "[F" => { VMValEnum::VMValFloat { val: FLOAT_ZERO } }
                "[D" => { VMValEnum::VMValDouble { val: DOUBLE_ZERO } }
                &_ => { VMValEnum::VMValRef { val: NULL_REF } }
            };
        }
        return VMValEnum::VMValRef { val: NULL_REF };
    }
}
